package com.young.ums.service.impl;

import com.young.common.exception.BaseException;
import com.young.common.util.CommonUtil;
import com.young.common.core.dal.service.IDataAccessService;
import com.young.common.util.Page;
import com.young.common.util.StringUtils;
import com.young.interfaces.log.annotation.Log;
import com.young.ums.core.ETopic;
import com.young.ums.core.PublishSubscribeCenter;
import com.young.ums.model.Dept;
import com.young.ums.model.Role;
import com.young.ums.model.enums.ERoleOpenTypeEnum;
import com.young.common.model.enums.ETrashFlagEnum;
import com.young.ums.service.IDataAuthService;
import com.young.ums.service.IDeptService;
import com.young.ums.service.IRoleService;
import com.young.ums.service.IRoleUserService;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
* 角色服务实现
* Created by imrookie on 2018-9-30.
*/
@Service("roleService")
public class RoleServiceImpl implements IRoleService {

    @Resource(name = "dataAccessService")
    IDataAccessService dataAccessService;//数据层服务

    @Resource
    PublishSubscribeCenter publishSubscribeCenter;

    @Resource(name = "dataAuthService")
    IDataAuthService dataAuthService;

    @Resource
    IDeptService deptService;

    @Resource
    IRoleUserService roleUserService;

    private static final Logger logger = LoggerFactory.getLogger(RoleServiceImpl.class);

    private static final String MAPPER = "com.young.ums.mapper.role";//mapper的namespace

    //获取数据列表
    @Log("查询角色列表")
    @Override
    public List<Role> getList(Role obj) {
        //权限参数处理
        dataAuthService.handleAuthorityParameter(obj);
        if (obj.getTrashFlag() == null){
            obj.setTrashFlag(ETrashFlagEnum.VALID.type);//默认查询未删除
        }
        return dataAccessService.getList(MAPPER + ".getList", obj);
    }

    //获取数据列表(分页)
    @Log("分页查询角色列表")
    @Override
    public List<Role> getPage(Role obj, Page page) {
        //权限参数处理
        dataAuthService.handleAuthorityParameter(obj);
        if (obj.getTrashFlag() == null){
            obj.setTrashFlag(ETrashFlagEnum.VALID.type);//默认查询未删除
        }
        return dataAccessService.getList(MAPPER + ".getList", obj, page);
    }

    /**
     * 根据单位id查询角色列表
     *
     * @param companyId
     * @return
     */
    @Log("根据单位id查询角色列表")
    @Override
    public List<Role> getListByCompanyId(String companyId) {
        Role obj = new Role();
        obj.setCompanyId(companyId);
        return this.getList(obj);
    }

    /**
     * 查询指定单位下的公开角色
     *
     * @param companyId 归属单位
     * @param open      角色公开类型,枚举:UmsConstants.RoleOpen
     * @return
     */
    @Log("查询指定单位下的公开角色")
    @Override
    public List<Role> getListByCompanyIdAndOpen(String companyId, int open) {
        Role obj = new Role();
        obj.setCompanyId(companyId);
        obj.setOpen(open);
        return this.getList(obj);
    }

    /**
     * 查询入参单位的直属上级中开放给直属下级使用的角色
     *
     * @param companyIds
     * @return
     */
    @Log("查询入参单位的直属上级中开放给直属下级使用的角色")
    @Override
    public List<Role> getParentOpenToDirectChildRoleList(List<String> companyIds) {
        if (companyIds == null || companyIds.size() == 0) {
            return null;
        }
        List<Role> list = new ArrayList<Role>();
        for (String companyId : companyIds) {
            Dept dept = deptService.getParentCompany(companyId);
            if (dept != null) {
                //查询该单位的角色类型为向直属下级开放的角色
                List<Role> roleList = this.getListByCompanyIdAndOpen(dept.getId(), ERoleOpenTypeEnum.DIRECT_CHILD.type);
                if (roleList != null && roleList.size() > 0) {
                    list.addAll(roleList);
                }
            }
        }
        return list;
    }

    /**
     * 查询入参单位的所有上级中开放给所有下级使用的角色
     *
     * @param companyIds
     * @return
     */
    @Log("查询入参单位的所有上级中开放给所有下级使用的角色")
    @Override
    public List<Role> getAllParentOpenToAllChildRoleList(List<String> companyIds) {
        if (companyIds == null || companyIds.size() == 0) {
            return null;
        }
        List<Role> list = new ArrayList<Role>();
        for (String companyId : companyIds) {
            //查询所有上级单位
            List<Dept> deptList = deptService.getAllParentCompany(companyId);
            logger.info("[查询入参单位能使用的向所有下级公开的角色] 单位[{}]的所有上级单位为:{}", companyId, deptList);
            if (deptList != null && deptList.size() > 0) {
                for (Dept dept : deptList) {
                    //查询该单位的角色类型为向直属下级开放的角色
                    List<Role> roleList = this.getListByCompanyIdAndOpen(dept.getId(), ERoleOpenTypeEnum.ALL_CHILD.type);
                    if (roleList != null && roleList.size() > 0) {
                        list.addAll(roleList);
                    }
                }
            }
        }
        return list;
    }

    /**
     * 查询开放给入参单位使用的角色
     * getParentOpenToDirectChildRoleList + getAllParentOpenToAllChildRoleList
     *
     * @param companyIds
     * @return
     */
    @Log("查询开放给入参单位使用的角色")
    @Override
    public List<Role> getOpenToCompanyRoleList(List<String> companyIds) {
        List<Role> list = this.getParentOpenToDirectChildRoleList(companyIds);
        if (list == null) {
            list = new ArrayList<Role>();
        }
        List<Role> list2 = this.getAllParentOpenToAllChildRoleList(companyIds);
        if (list2 != null && list2.size() > 0) {
            list.addAll(list2);
        }
        return list;
    }

    //查询单条
    @Log("查询角色")
    @Override
    public Role get(String id) {
        return dataAccessService.getObject(MAPPER + ".get", id);
    }

    /**
     * 根据角色id集合批量查询角色信息
     *
     * @param roleIds 角色id集合
     * @return
     */
    @Log("根据角色id集合批量查询角色信息")
    @Override
    public List<Role> getListByIds(List<String> roleIds) {
        return dataAccessService.getList(MAPPER + ".getListByIds", roleIds);
    }

    //统计数量
    @Log("角色计数")
    @Override
    public int count(Role obj) {
        return dataAccessService.getObject(MAPPER + ".count", obj);
    }

    //修改
    @Log("修改角色")
    @Override
    public int update(Role obj) {
        if (obj == null || StringUtils.isBlank(obj.getId())) {
            throw new BaseException("角色修改失败:入参无效");
        }
        Role oldRole = this.get(obj.getId());
        //当修改前的角色公开类型为部分单位公开且发生改动时,删除角色单位关联关系
        if (ERoleOpenTypeEnum.SOME_CHILD.eq(oldRole.getOpen()) && obj.getOpen() != null && !oldRole.getOpen().equals(obj.getOpen())) {
            logger.info("[修改角色] 角色[{}]原先的公开类型为:向部分下级单位公开,改变为:{},向订阅中心发出消息通知", obj.getId(), obj.getOpen());
            //向发布订阅中心发布角色公开类型由部分公开改变的消息
            publishSubscribeCenter.publish(ETopic.ROLE_OPEN_TO_SOME_CHILD_CHANGE, obj.getId());
        }
        obj.setUpdateTime(new Date());
        return dataAccessService.update(MAPPER + ".update", obj);
    }

    //批量删除
    @Log("批量删除角色")
    @Override
    public int delete(String[] idArr) {
        int i = 0;
        for(String id : idArr){
            i += this.delete(id);
        }
        return i;
    }

    //删除单条
    @Log("删除角色")
    @Override
    public int delete(String id) {
        //向发布订阅中心发布用户删除消息
        publishSubscribeCenter.publish(ETopic.ROLE_DEL, id);
        return dataAccessService.delete(MAPPER + ".delete", id);
    }

    //插入
    @Log("插入角色")
    @Override
    public int insert(Role obj) {
        if (StringUtils.isBlank(obj.getId())){
            obj.setId(CommonUtil.getUUID());
        }
        obj.setCreateTime(new Date());
        obj.setUpdateTime(new Date());
        obj.setTrashFlag(ETrashFlagEnum.VALID.type);//未删除
        return dataAccessService.insert(MAPPER + ".insert", obj);
    }

    //批量插入
    @Log("批量插入角色")
    @Override
    public int batchInsert(List<Role> list) {
        int i = 0;
        for(Role item : list){
            i += this.insert(item);
        }
        return i;
    }

    /**
     * 根据用户id查询关联角色列表
     *
     * @param userId
     * @return
     */
    @Log("根据用户id查询关联角色列表")
    @Override
    public List<Role> getRoleListByUserId(String userId) {
        //根据用户id查询关联的角色id
        String[] roleIds = roleUserService.getRoleIdsByUserId(userId);
        if (roleIds != null && roleIds.length > 0) {
            return this.getListByIds(Arrays.asList(roleIds));
        }
        return null;
    }

}